#include "qrender/render_manager.h"

// QOpenGL 相关
#include <QOpenGLVertexArrayObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOffscreenSurface>
#include <QOpenGLFramebufferObject>
#include <QOpenGLExtraFunctions>
#include <QOpenGLTexture>

#include <QMetaObject>
#include <QAbstractEventDispatcher>
#include <QApplication>
#include <QThread>
#include <QTime>

#include <qrender/render_view.h>
#include <qrender/camera.h>
#include <qrender/renderer.h>

RenderManager::RenderManager(RenderView *render_form)
    : QObject(nullptr), render_form_(render_form)
{
    camera_.reset(new Camera(render_form));

    thread_ = new QThread();
    moveToThread(thread_);
    thread_->start();
}

RenderManager::~RenderManager()
{
    thread_->quit();
    thread_->wait();
    delete thread_;
}

void RenderManager::addRenderer(std::shared_ptr<Renderer> renderer)
{
    if (!renderer) {
        return;
    }

    QMutexLocker lk(&mtx_renderers_);
    renderers_ << renderer;

    // add 无需 create, render 时会调用
}

void RenderManager::removeRenderer(std::shared_ptr<Renderer> renderer)
{
    if (!renderer) {
        return;
    }

    {
        QMutexLocker lk(&mtx_renderers_);
        renderers_.removeOne(renderer);
    }

    // 移除的渲染对象要释放资源
    QMetaObject::invokeMethod(
        QAbstractEventDispatcher::instance(thread_),
        [=] {
            // 确保上下文是当前的，然后明确销毁所有底层 OpenGL 资源
            ctx_->makeCurrent(render_form_->surface_);
            renderer->requestRelease();
            ctx_->doneCurrent();
        },
        Qt::QueuedConnection);
}

void RenderManager::requestInit()
{
    QMetaObject::invokeMethod(
        QAbstractEventDispatcher::instance(thread_), [=] { init(); },
        Qt::QueuedConnection);
}

void RenderManager::requestResize()
{
    QMetaObject::invokeMethod(
        QAbstractEventDispatcher::instance(thread_),
        [=] { resize(render_form_->width(), render_form_->height()); },
        Qt::QueuedConnection);
}

void RenderManager::requestRender()
{
    QMetaObject::invokeMethod(
        QAbstractEventDispatcher::instance(thread_), [=] { render(); },
        Qt::QueuedConnection);
}

void RenderManager::requestStop()
{
    QMetaObject::invokeMethod(
        QAbstractEventDispatcher::instance(thread_), [=] { cleanup(); },
        Qt::QueuedConnection);
}

std::shared_ptr<Camera> RenderManager::getCamera()
{
    return camera_;
}

void RenderManager::ensureFbo()
{
    if (fbo_ && fbo_->size() !=
                    render_form_->size() * render_form_->devicePixelRatio()) {
        delete fbo_;
        fbo_ = nullptr;
    }

    if (!fbo_) {
        fbo_ = new QOpenGLFramebufferObject(
            render_form_->size() * render_form_->devicePixelRatio(),
            QOpenGLFramebufferObject::CombinedDepthStencil);
    }
}

void RenderManager::init()
{
    QMutexLocker lk(&mtx_renderers_);

    ctx_.reset(new QOpenGLContext());
    ctx_->setShareContext(render_form_->context());
    ctx_->setScreen(render_form_->context()->screen());
    ctx_->setFormat(render_form_->context()->format());
    ctx_->create();
    if (!ctx_->makeCurrent(render_form_->surface_)) {
        qWarning("Failed to make context current on render thread");
        return;
    }

    QOpenGLFunctions *f = ctx_->functions();
    f->initializeOpenGLFunctions();
    f->glEnable(GL_DEPTH_TEST);

    for (auto &renderer : renderers_) {
        renderer->requestCreate();
    }

    ctx_->doneCurrent();
}

void RenderManager::resize(int w, int h)
{
    camera_->setProjectionMatrix(45.0, 1.0 * w / h, 0.01, 6000.0);
}

void RenderManager::render()
{
    // 执行实际的渲染任务
    if (!ctx_) {
        init();
    }

    QMutexLocker lk(&mtx_renderers_);

    if (!ctx_->makeCurrent(render_form_->surface_)) {
        return;
    }

    // 将渲染数据绘制到子线程的帧缓冲区中
    ensureFbo();
    fbo_->bind();

    // 默认初始化
    QOpenGLFunctions *f = ctx_->functions();
    f->glClearColor(1.0, 1.0, 1.0, 1.0);
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    f->glViewport(0, 0, fbo_->size().width(), fbo_->size().height());
    f->glEnable(GL_BLEND); // 启用混合模式
    f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 根据相机参数渲染全部数据
    auto camera = camera_->getInfo();
    for (auto &renderer : renderers_) {
        renderer->requestRender(camera);
    }

    f->glEnable(GL_BLEND);

    fbo_->release();

    ctx_->doneCurrent();

    // 通知主线程同步帧缓冲区
    emit blitFramebuffer();

    cond_render_.wakeOne();
}

void RenderManager::cleanup()
{
    // 确保上下文是当前的，然后明确销毁所有底层 OpenGL 资源
    QMutexLocker lk(&mtx_renderers_);

    if (ctx_) {
        ctx_->makeCurrent(render_form_->surface_);

        delete fbo_;
        fbo_ = nullptr;

        for (auto &renderer : renderers_) {
            renderer->requestRelease();
        }

        ctx_->doneCurrent();

        ctx_.reset();
    }

    cond_render_.wakeOne();
}
